/***
 *  Platypus: Page Layout and Typesetting Software (free at platypus.pz.org)
 *
 *  Platypus is (c) Copyright 2006-12 Pacific Data Works LLC. All Rights Reserved.
 *  Licensed under Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0.html)
 */

package org.pz.platypus;

import com.google.common.annotations.VisibleForTesting;
import org.pz.platypus.commandTypes.Symbol;
import org.pz.platypus.exceptions.StopExecutionException;
import org.pz.platypus.interfaces.ICommand;

import java.util.*;

import static com.google.common.base.Preconditions.*;

/**
 * Table of all supported commands in Platypus. It's implemented using a key consisting
 * of the command root (a String that is long enough to uniquely identify the command).
 * All commands in the Platypus file are looked up in here; Command object that is
 * returned contains all the info for parsing the command.
 *
 * @author alb
 */
@SuppressWarnings("unchecked")
public class CommandTable
{
    /** the hashtable into which the commands are loaded */
    protected HashMap<String, ICommand> commandTable;

    private GDD gdd;

    /**
     * This constructor is included here only because it facilitates writing
     * mock Literals class for testing. It's not called from Platypus working code.
     */
    @VisibleForTesting
    public CommandTable()
    {
        super();
    }

    public CommandTable( final GDD Gdd )
    {
        gdd = checkNotNull( Gdd );
        checkNotNull( gdd.log, "Logger in GDD is null in CommandTable()" );
        commandTable = new HashMap<String, ICommand>( 300 );
    }

    /**
     * Load the commands and symbols into the command table.
     * Commands are loaded in alpha order
     */
    public void load()
    {
        try {
            CommandTableLoader comLoader = new CommandTableLoader( gdd );
            comLoader.load( gdd.homeDirectory + "config" + gdd.fileSeparator + "Commands.properties" );

            loadRemainingCommands();
        }
        catch( Throwable t ) {
            throw new StopExecutionException( "Unable to load commands into CommandTable" );
        }

        loadSymbols();
        gdd.diag( "Command table in Platypus loaded with " + commandTable.size() + " commands" );
    }

    /**
     * Family commands are not generally load-able from the property file;
     * so they have to be loaded manually, as done here.
     */
    void loadRemainingCommands()
    {
// commented out top line to shut up error msgs when porting to Platypus-3
//        add( new FontFamily() );
/////>>>        add( new DefUserString() );
    }

    /**
     * load symbols and special characters. These are loaded from a text file.
     */
    void loadSymbols()
    {
        SymbolsList sl = new SymbolsList( gdd );
        sl.load();
        List<String> symbols = sl.getList();
        for( String symbol : symbols ) {
            add( new Symbol( symbol ));
        }
    }

    /**
     * add an ICommand item to the hash table, using its root as the key to the entry
     * @param entry to be added (either a command or a symbol)
     */
    public void add( ICommand entry )
    {
        commandTable.put( entry.getRoot(), entry );
    }

    public int size()
    {
        return( commandTable.size() );
    }
    //=== getters and setters ===/

    /**
     * Lookup a command by its root
     * @param root command root (portion ending in the first | : or ] character
     * @return the Commandable class found, or null on error
     */
    public ICommand getCommand( final String root )
    {
        return( (ICommand) commandTable.get( root ));
    }
}
